import sys
import os
from PySide6.QtGui import QFont, QIcon
from matplotlib.ticker import FuncFormatter, PercentFormatter
import pandas as pd
import numpy as np
from PySide6.QtWidgets import QApplication, QFrame, QGridLayout, QMainWindow, QMessageBox, QPushButton, QSizePolicy, QSpacerItem, QTableWidget, QTableWidgetItem, QTextEdit, QVBoxLayout, QWidget, QFileDialog, QScrollArea, QDialog, QLineEdit, QLabel, QFormLayout, QHBoxLayout
from PySide6.QtCore import QSize, Qt
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
import matplotlib.pyplot as plt
import re
from PySide6.QtGui import QAction
from PySide6.QtWidgets import QToolBar

# 定义元素的摩尔质量字典
element_molar_mass = {'Ca': 40.08,
                      'Ce': 140.12,
                      'Mg': 24.31,
                      'Al': 26.98,
                      'Ti': 47.87,
                      'Li': 6.94,
                      'Si': 28.09,
                      'B': 10.81,
                      'V': 50.94,
                      'Mn': 54.94,
                      'Nb': 92.91,
                      'Cr': 52,
                      'Fe': 55.85,
                      'Na': 23,
                      'K': 39.1,
                      'C': 12.01,
                      'N': 14.01,
                      'O': 16,
                      'F': 19,
                      'S': 32.06,
                      'Cl': 35.45}

# 定义元素的质量分数字典，初始化为0，后续可单独赋值
element_mass_fractions = {'Ca': 0,
                          'Ce': 0,
                          'Mg': 0,
                          'Al': 0,
                          'Ti': 0,
                          'Li': 0,
                          'Si': 0,
                          'B': 0,
                          'V': 0,
                          'Mn': 0,
                          'Nb': 0,
                          'Cr': 0,
                          'Fe': 0,
                          'Na': 0,
                          'K': 0,
                          'C': 0,
                          'N': 0,
                          'O': 30,
                          'F': 0,
                          'S': 0,
                          'Cl': 0}

total_mass = 100  # 总质量


class ExcelViewer(QMainWindow):
    def __init__(self):
        super().__init__()

        # 设置窗口图标  
        self.setWindowIcon(QIcon(r'C:\Users\11421\Desktop\BG_Inclusion_analysis\BGlogo.png'))  # 替换为您的 logo 路径
        self.setWindowTitle("非金属夹杂物溯源")  
        self.setGeometry(150, 30, 1400, 950)  
        
        # 创建菜单栏
        self.menu_bar = self.menuBar()
        # 创建“文件”菜单
        file_menu = self.menu_bar.addMenu("文件")
        file_menu.addAction(self.create_action("新建", self.new_file, "document-new"))
        file_menu.addAction(self.create_action("打开", self.open_file, "document-open"))
        file_menu.addAction(self.create_action("保存", self.save_file, "document-save"))
        file_menu.addAction(self.create_action("打印", self.print_file, "document-print"))
        file_menu.addAction(self.create_action("退出", self.exit_app))

        # 创建“编辑”菜单
        edit_menu = self.menu_bar.addMenu("编辑")
        edit_menu.addAction(self.create_action("撤销", self.undo, "edit-undo"))
        edit_menu.addAction(self.create_action("重做", self.redo, "edit-redo"))
        edit_menu.addAction(self.create_action("剪切", self.cut, "edit-cut"))
        edit_menu.addAction(self.create_action("复制", self.copy, "edit-copy"))
        edit_menu.addAction(self.create_action("粘贴", self.paste, "edit-paste"))
        edit_menu.addAction(self.create_action("删除", self.delete, "edit-delete"))
        edit_menu.addAction(self.create_action("插入", self.insert))
        edit_menu.addAction(self.create_action("查找", self.find))

        # 创建“数据”菜单
        data_menu = self.menu_bar.addMenu("数据")
        data_menu.addAction(self.create_action("连接到文件", self.connect_to_file))
        data_menu.addAction(self.create_action("连接到数据库", self.connect_to_database))
        data_menu.addAction(self.create_action("数据筛选", self.filter_data))

        # 创建“帮助”菜单
        help_menu = self.menu_bar.addMenu("帮助")
        help_menu.addAction(self.create_action("帮助文档", self.show_help))
        help_menu.addAction(self.create_action("注册", self.register))
        help_menu.addAction(self.create_action("关于", self.about))

        # 创建工具栏
        self.toolbar = QToolBar("工具栏", self)
        self.addToolBar(self.toolbar)
        # 设置工具栏按钮样式：图标在上，文字在下
        self.toolbar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
        # 方式1：设置图标大小  
        self.toolbar.setIconSize(QSize(18, 18))  # 设置图标大小为16x16像素  
        # 添加工具栏按钮
        self.toolbar.addAction(self.create_action("新建", self.new_file, "document-new"))
        self.toolbar.addAction(self.create_action("打开", self.open_file, "document-open"))
        self.toolbar.addAction(self.create_action("保存", self.save_file, "document-save"))
        self.toolbar.addSeparator()  # 添加分隔符
        self.toolbar.addAction(self.create_action("撤销", self.undo, "edit-undo"))
        self.toolbar.addAction(self.create_action("重做", self.redo, "edit-redo"))
        self.toolbar.addSeparator()  # 添加分隔符
        self.toolbar.addAction(self.create_action("打印", self.print_file, "document-print")) 


        # 在创建主布局之前，添加标签  
        self.label1 = QLabel("非金属夹杂物成分转换")  # 创建标签并设置文本内容  
        self.label1.setAlignment(Qt.AlignLeft)  # 设置文本居中对齐  

        # 设置标签的样式  
        self.label1.setStyleSheet("""  
            background-color: rgb(68, 114, 196);  /* 背景色为浅蓝色 */  
            color: white;            /* 字体颜色为白色 */  
            font-family: 'Microsoft YaHei';    /* 使用字体 */ 
            font-size: 14px;            /* 字体大小为18 */   
            font-weight: bold;       /* 字体加粗 */  
            padding: 8px;           /* 内边距，确保标签不太高 */  
        """)  

        # 在创建主布局之前，添加标签  
        self.label2 = QLabel("非金属夹杂物来源判断")  # 创建标签并设置文本内容  
        self.label2.setAlignment(Qt.AlignLeft)  # 设置文本居中对齐  

        # 设置标签的样式  
        self.label2.setStyleSheet("""  
            background-color: rgb(68, 114, 196);  /* 背景色为浅蓝色 */  
            color: white;            /* 字体颜色为白色 */  
            font-family: 'Microsoft YaHei';    /* 使用字体 */ 
            font-size: 14px;            /* 字体大小为18 */   
            font-weight: bold;       /* 字体加粗 */  
            padding: 8px;           /* 内边距，确保标签不太高 */  
        """)  

        # 创建分隔线  
        self.heixian1 = QFrame()  
        self.heixian1.setFrameShape(QFrame.HLine)  # 设置为水平线  
        self.heixian1.setFrameShadow(QFrame.Sunken)  # 设置阴影效果为凹陷  
        self.heixian1.setStyleSheet("QFrame { border: 0.5px solid #ADD8E6; }")  # 设置线条颜色为黑色，厚度为1个像素  
        # 创建分隔线  
        self.heixian2 = QFrame()  
        self.heixian2.setFrameShape(QFrame.HLine)  # 设置为水平线  
        self.heixian2.setFrameShadow(QFrame.Sunken)  # 设置阴影效果为凹陷  
        self.heixian2.setStyleSheet("QFrame { border: 0.5px solid #ADD8E6; }")  # 设置线条颜色为黑色，厚度为1个像素 

        # 创建按钮并设置最小高度和固定大小  导入数据按钮
        self.button_load = QPushButton("导入数据")  
        self.button_load.setMinimumHeight(70)  
        self.button_load.setFixedWidth(120)  
        self.button_load.clicked.connect(self.load_excel)  
        # 设置按钮的样式  
        self.button_load.setStyleSheet("""  
            QPushButton {  
                background-color: rgb(91, 155, 213);  /* 默认背景色 */  
                color: white;                /* 字体颜色为白色 */  
                font-family: 'Microsoft YaHei';  /* 使用微软雅黑字体 */  
                font-size: 13px;            /* 设置字体大小，可以根据需要调整 */   
                font-weight: bold;       /* 字体加粗 */   
                padding: 5px;               /* 内边距 */  
                border: none;               /* 去掉边框 */  
                border-radius: 5px;        /* 设置圆角 */  
            }  
            QPushButton:hover {  
                background-color: rgb(85, 170, 255);  /* 鼠标悬停时的颜色 */  
            }  
            QPushButton:pressed {  
                background-color: rgb(91, 155, 213);  /* 按下时的颜色 */  
            }  
        """)

        # 创建按钮并设置最小高度和固定大小  输入数据按钮
        self.button_input = QPushButton("输入数据")  
        self.button_input.setMinimumHeight(70)  
        self.button_input.setFixedWidth(120)  
        self.button_input.clicked.connect(self.open_input_dialog)  
        # 设置按钮的样式  
        self.button_input.setStyleSheet("""  
            QPushButton {  
                        background-color: rgb(91, 155, 213);  /* 默认背景色 */  
                        color: white;                /* 字体颜色为白色 */  
                        font-family: 'Microsoft YaHei';  /* 使用微软雅黑字体 */  
                        font-size: 13px;            /* 设置字体大小，可以根据需要调整 */   
                        font-weight: bold;       /* 字体加粗 */   
                        padding: 5px;               /* 内边距 */  
                        border: none;               /* 去掉边框 */  
                        border-radius: 5px;        /* 设置圆角 */  
                    }  
                    QPushButton:hover {  
                        background-color: rgb(85, 170, 255);  /* 鼠标悬停时的颜色 */  
                    }  
                    QPushButton:pressed {  
                        background-color: rgb(91, 155, 213);  /* 按下时的颜色 */  
                    }  
                """)

        # 创建按钮并设置最小高度和固定大小  成分转换按钮
        self.button_convert = QPushButton("成分转换")  
        self.button_convert.setMinimumHeight(70)  
        self.button_convert.setFixedWidth(120)  
        self.button_convert.clicked.connect(self.convert_elements)  
        # 设置按钮的样式  
        self.button_convert.setStyleSheet("""  
            QPushButton {  
                background-color: rgb(91, 155, 213);  /* 默认背景色 */  
                color: white;                /* 字体颜色为白色 */  
                font-family: 'Microsoft YaHei';  /* 使用微软雅黑字体 */  
                font-size: 13px;            /* 设置字体大小，可以根据需要调整 */   
                font-weight: bold;       /* 字体加粗 */   
                padding: 5px;               /* 内边距 */  
                border: none;               /* 去掉边框 */  
                border-radius: 5px;        /* 设置圆角 */  
            }  
            QPushButton:hover {  
                background-color: rgb(85, 170, 255);  /* 鼠标悬停时的颜色 */  
            }  
            QPushButton:pressed {  
                background-color: rgb(91, 155, 213);  /* 按下时的颜色 */  
            }  
        """)

        # 创建按钮并设置最小高度和固定大小  保存数据按钮
        self.button_saveA = QPushButton("保存数据")  
        self.button_saveA.setMinimumHeight(70)  
        self.button_saveA.setFixedWidth(120)  
        # 设置按钮的样式  
        self.button_saveA.setStyleSheet("""  
            QPushButton {  
                background-color: rgb(91, 155, 213);  /* 默认背景色 */  
                color: white;                /* 字体颜色为白色 */  
                font-family: 'Microsoft YaHei';  /* 使用微软雅黑字体 */  
                font-size: 13px;            /* 设置字体大小，可以根据需要调整 */   
                font-weight: bold;       /* 字体加粗 */   
                padding: 5px;               /* 内边距 */  
                border: none;               /* 去掉边框 */  
                border-radius: 5px;        /* 设置圆角 */  
            }  
            QPushButton:hover {  
                background-color: rgb(85, 170, 255);  /* 鼠标悬停时的颜色 */  
            }  
            QPushButton:pressed {  
                background-color: rgb(91, 155, 213);  /* 按下时的颜色 */  
            }  
        """)


        # 创建表格  1  导入数据表格
        self.table_widget = QTableWidget()  
        self.table_widget.setMinimumSize(100, 100) 
        # 设置标题字体大小  
        header_font = QFont("Times New Roman", 12)  # 可以根据需要选择字体和大小  
        self.table_widget.horizontalHeader().setFont(header_font) 
        # 设置字体大小  
        font = QFont("Times New Roman", 10)  # 选择字体和字号，可以根据需要调整  
        self.table_widget.setFont(font)  # 设置表格字体  
        # 设置表格的样式，包括蓝色边框  
        self.table_widget.setStyleSheet("""  
            border: 0.5px solid #D3D3D3;  /* 设置边框为蓝色，厚度为0.5px */  
            border-radius: 2px;          /* 可选：使边框圆角 */  
        """)  

        # 定义列标题  
        self.column_headers = ['文件夹名', '夹杂物序号','CaF2', 'CaO',   
            'CeO', 'MgO', 'Al2O3', 'Ti2O3', 'Li2O',   
            'SiO2', 'B2O3', 'V2O3', 'MnO', 'NbO2', 'Cr2O3', 'FeO',   
            'Na2O', 'K2O', 'TiN', 'AlN', 'CeS', 'TiS', 'MnS'  
            ]  

        # 创建表格  2   计算结果表格
        self.oxide_results_table = QTableWidget()  
        self.oxide_results_table.setMinimumSize(700, 200)  
        self.oxide_results_table.setColumnCount(len(self.column_headers))  
        # self.oxide_results_table.setHorizontalHeaderLabels(self.column_headers)  

        # 添加下标  
        formatted_column_headers = []  
        for category1 in self.column_headers:  
            if category1:  # 如果不是空字符串  
                # 直接替换数字为对应的 Unicode 下标字符  
                formatted = category1.replace('2', '₂').replace('3', '₃')  
                formatted_column_headers.append(formatted)  
            else:  
                formatted_column_headers.append("")  # 添加空字符串   
        # 将格式化后的列标题设置为表头  
        self.oxide_results_table.setHorizontalHeaderLabels(formatted_column_headers) 

        # 设置字体大小  
        font = QFont("Times New Roman", 10)  # 选择字体和字号，可以根据需要调整  
        # 设置标题字体大小  
        column_headers = QFont("Times New Roman", 10)  # 可以根据需要选择字体和大小 
        column_headers.setBold(False)  # 设置字体加粗  
        self.oxide_results_table.horizontalHeader().setFont(column_headers) 
        # 通过设置固定高度来调整表头高度  
        header_height = 40  # 可以根据需要调整高度  
        self.oxide_results_table.horizontalHeader().setFixedHeight(header_height)  


        self.oxide_results_table.setFont(font)  # 设置表格字体  
        # 设置表格的样式，包括蓝色边框  
        self.oxide_results_table.setStyleSheet("""  
            border: 0.5px solid #D3D3D3;  /* 设置边框为蓝色，厚度为0.5px */  
            border-radius: 2px;          /* 可选：使边框圆角 */  
        """) 

        
        
        # 将单元格点击信号连接到自定义的处理函数  
        self.table_widget.cellClicked.connect(self.handle_cell_click)  

        # 创建滚动区域并设置尺寸  滚动区域内装table_widget
        # scroll_area = QScrollArea()  
        # scroll_area.setWidget(self.table_widget)  
        # scroll_area.setWidgetResizable(True)  

        # # 隐藏外部滚动条  
        # scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)  
        # scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)  

        # 创建下半部分的布局  
        lower_layout = QGridLayout()  
        bottom_left_layout = QVBoxLayout()  

        # 夹杂物来源按钮    及其文本框  
        self.button_source = QPushButton("夹杂物来源")  
        self.button_source.setMinimumHeight(40) 
        self.button_source.clicked.connect(self.source_elements) 
        self.text_source = QTextEdit()  
        self.text_source.setPlaceholderText("") 
        # 设置按钮的样式  
        self.button_source.setStyleSheet("""  
             QPushButton {  
                background-color: rgb(91, 155, 213);  /* 默认背景色 */  
                color: white;                /* 字体颜色为白色 */  
                font-family: 'Microsoft YaHei';  /* 使用微软雅黑字体 */  
                font-size: 13px;            /* 设置字体大小，可以根据需要调整 */   
                font-weight: bold;       /* 字体加粗 */   
                padding: 5px;               /* 内边距 */  
                border: none;               /* 去掉边框 */  
                border-radius: 5px;        /* 设置圆角 */  
            }  
            QPushButton:hover {  
                background-color: rgb(85, 170, 255);  /* 鼠标悬停时的颜色 */  
            }  
            QPushButton:pressed {  
                background-color: rgb(91, 155, 213);  /* 按下时的颜色 */  
            }  
        """)
        # 设置 QTextEdit 的样式  
        self.text_source.setStyleSheet("""   
            border: 1px solid #A0A0A0;  /* 可选：添加边框，为其变得更明显 */  
            font-family: 'Microsoft YaHei';  /* 使用微软雅黑字体（可选） */  
            font-size: 14px;  /* 字体大小（可选） */  
            padding: 5px;  /* 内边距（可选） */  
        """)

        # 建议解决方案按钮    及其文本框  
        self.button_suggestion = QPushButton("建议解决方案")  
        self.button_suggestion.setMinimumHeight(40)
        self.button_suggestion.clicked.connect(self.suggestion_elements)
        self.text_suggestion = QTextEdit()  
        self.text_suggestion.setPlaceholderText("") 
        #稳定拉速、稳定过热度、稳定浸入水口插入深度
        # 设置按钮的样式  
        self.button_suggestion.setStyleSheet("""  
            QPushButton {  
                background-color: rgb(91, 155, 213);  /* 默认背景色 */  
                color: white;                /* 字体颜色为白色 */  
                font-family: 'Microsoft YaHei';  /* 使用微软雅黑字体 */  
                font-size: 13px;            /* 设置字体大小，可以根据需要调整 */   
                font-weight: bold;       /* 字体加粗 */   
                padding: 5px;               /* 内边距 */  
                border: none;               /* 去掉边框 */  
                border-radius: 5px;        /* 设置圆角 */  
            }  
            QPushButton:hover {  
                background-color: rgb(85, 170, 255);  /* 鼠标悬停时的颜色 */  
            }  
            QPushButton:pressed {  
                background-color: rgb(91, 155, 213);  /* 按下时的颜色 */  
            }  
        """)
        # 设置 QTextEdit 的样式  
        self.text_suggestion.setStyleSheet("""  
            border: 1px solid #A0A0A0;  /* 可选：添加边框，为其变得更明显 */  
            font-family: 'Microsoft YaHei';  /* 使用微软雅黑字体（可选） */  
            font-size: 14px;  /* 字体大小（可选） */  
            padding: 5px;  /* 内边距（可选） */  
        """)

        # 组织左下角布局  
        bottom_left_layout.addWidget(self.button_source)  
        bottom_left_layout.addWidget(self.text_source)  
        bottom_left_layout.addWidget(self.button_suggestion)  
        bottom_left_layout.addWidget(self.text_suggestion)  

        # 创建柱状图作为控件  
        self.canvas = FigureCanvas(Figure(figsize=(10, 3.5)))  
        self.ax = self.canvas.figure.add_subplot(111) 
        

        # 设置柱状图的横坐标  
        categories = ["", "CaF2", "CaO", "CeO", "MgO", "Ti2O3", "Li2O", "TiO2", "SiO2",   
                    "B2O3", "V2O3", "MnO", "NbO2", "Cr2O3","FeO", "Na2O", "K2O",  
                    "TiN", "AlN", "CeS", "TiS", "MnS", ""]  
                 
        # 转换化学式，添加下标  
        formatted_categories = []  
        for category in categories:  
            if category:  # 如果不是空字符串  
                # 使用正则表达式将数字转换为下标格式  
                formatted = re.sub(r'(\d+)', r'$_{\\mathregular{\1}}$', category)  
                formatted_categories.append(formatted)  
            else:  
                formatted_categories.append("")  

        # 设置x轴刻度位置和标签  
        self.ax.set_xticks(range(len(categories)))  
        self.ax.set_xticklabels(formatted_categories,   
                                rotation=45,  # 标签旋转45度  
                                ha='right',   # 水平对齐方式  
                                fontsize=10,  # 字体大小  
                                fontfamily='Times New Roman')  # 字体类型  

        # 设置图表标题  
        self.ax.set_title('夹杂物组成分布',   
                        fontproperties="SimHei",  # 中文用黑体  
                        fontsize=14,             # 标题字号  
                        fontweight='bold',       # 标题加粗  
                        pad=15)                  # 标题距离图表的距离  

        # 设置y轴标签  
        self.ax.set_ylabel('质量百分含量/%',   
                        fontproperties="SimHei",  # 中文用黑体  
                        fontsize=12,             # 字号  
                        fontweight='bold',       # 加粗  
                        labelpad=10)             # 标签距离轴的距离  

        # 设置y轴的范围和刻度  
        self.ax.set_ylim(0, 100)  # 设置y轴范围从0到100  
        y_ticks = range(0, 101, 20)  # 创建一个从0到100，步长为20的刻度列表  
        self.ax.set_yticks(y_ticks)  # 设置y轴刻度  
       
        # 设置y轴刻度标签字体为Times New Roman  
        self.ax.set_yticklabels(y_ticks,   
                        fontfamily='Times New Roman',  # 设置字体为Times New Roman  
                        fontsize=10)  # 设置字体大小
       
        # 设置x轴刻度样式  
        self.ax.tick_params(axis='x',               # 只应用于x轴  
                            labelsize=10,           # 刻度标签字号  
                            length=3,               # 刻度线长度  
                            width=1,                # 刻度线宽度  
                            direction='in',         # 刻度线朝向  
                            top=False)               # 显示上边框刻度线  

        # 设置y轴刻度样式  
        self.ax.tick_params(axis='y',               # 只应用于y轴  
                            labelsize=10,           # 刻度标签字号  
                            length=3,               # 刻度线长度  
                            width=1,                # 刻度线宽度  
                            direction='in',         # 刻度线朝向  
                            right=False)             # 显示右边框刻度线

        # 设置坐标轴线条样式  
        for spine in ['top', 'bottom', 'left', 'right']:  
            self.ax.spines[spine].set_linewidth(1.5)  # 设置坐标轴线条粗细  

        # 添加网格线  
        self.ax.grid(True,   
                    axis='y',                # 只显示水平网格线  
                    linestyle='--',          # 网格线样式为虚线  
                    alpha=0.3,               # 设置透明度  
                    color='gray')            # 设置颜色  

        # 调整布局，确保标签不被切掉  
        self.canvas.figure.tight_layout()
        self.canvas.draw()  

        # 将柱状图添加到右下侧布局  
        lower_layout.addLayout(bottom_left_layout, 0, 0)  
        lower_layout.addWidget(self.canvas, 0, 1)  
        
        # 创建主布局并添加组件 第一部分   
        layout1 = QGridLayout()  
        self.button_load.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)  
        self.button_input.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)  
        # layout1.addWidget(self.button_load, 0, 0)  
        # layout1.addWidget(self.button_input, 1, 0)  
        layout1.addWidget(self.button_load, 0, 0, Qt.AlignTop)  # 使用 AlignTop 让按钮靠上对齐  
        layout1.addWidget(self.button_input, 1, 0, Qt.AlignBottom)
        # layout1.addWidget(self.button_load, 0, 0)  # 第一行第一列  
        # layout1.addWidget(self.button_input, 1, 0)  # 第二行第一列  
        scroll_area = QScrollArea()  
        scroll_area.setWidget(self.table_widget)  
        scroll_area.setWidgetResizable(True)  
        scroll_area.setMinimumHeight(200)  
        scroll_area.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)  
        # 隐藏外部滚动条  
        scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)  
        scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)  
     
        # 设置表格的最小高度，例如 200  
        # scroll_area.setMinimumHeight(200)  # 设定最低高度  
        layout1.addWidget(scroll_area, 0, 1, 2, 1)  # 使用滚动区域显示表格，跨两行  

        # 设置尺寸策略以使控件响应窗口调整大小  
        # scroll_area.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)  # 允许水平和垂直方向扩展  
        # 设置列伸缩因子，使第二列（索引1）可以扩展  
        layout1.setRowStretch(1, 1)  # 让第二行可以伸缩
        layout1.setColumnStretch(1, 1)  # 让第二列可以伸缩 
        layout1.setColumnStretch(0, 1)  # 让第二列可以伸缩 
        # 添加垂直空间器让它的高度更高  
        spacer_item = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)  
        layout1.addItem(spacer_item, 2, 1)  # 在第二行增加空间器 

        # 第二部分
        layout2 = QGridLayout()  
        layout2.addWidget(self.button_convert, 0, 0)    # 第一行第一列  
        layout2.addWidget(self.button_saveA, 1, 0)    # 第二行第一列  
        layout2.addWidget(self.oxide_results_table, 0, 1, 2, 1)  # 对应的成分转换表格，跨两行  

        # 第三部分：创建日志文本框的布局  
        layout3 = QVBoxLayout()  # 创建一个新的垂直布局  
        self.log_textbox = QTextEdit()  
        self.log_textbox.setPlaceholderText("运行日志")  # 设置默认提示文本  
        self.log_textbox.setMaximumHeight(50)  # 设置最大高度为30  
        layout3.addWidget(self.log_textbox)  # 将文本框添加到布局中  
        # 设置 QTextEdit 的样式  
        self.log_textbox.setStyleSheet("""  
            border: 1px solid #A0A0A0;  /* 可选：添加边框，为其变得更明显 */  
            font-family: 'Microsoft YaHei';  /* 使用微软雅黑字体（可选） */  
            font-size: 14px;  /* 字体大小（可选） */  
            padding: 5px;  /* 内边距（可选） */  
        """)


        # 创建主布局并添加所有部分  
        main_layout = QVBoxLayout()  
        main_layout.addWidget(self.label1)  # 将标签添加到主布局的顶部
        main_layout.addLayout(layout1)  
        main_layout.addWidget(self.heixian2)  # 添加分隔线
        main_layout.addLayout(layout2)  
        main_layout.addWidget(self.label2)  # 将标签添加到下布局的上部
        main_layout.addLayout(lower_layout)  
        main_layout.addWidget(self.heixian1)  # 添加分隔线
        main_layout.addLayout(layout3) 

        # 创建主窗口的中心部件  
        container = QWidget() 
        container.setLayout(main_layout)  
        self.setCentralWidget(container)  

        # 设置内部表格的滚动条属性  
        self.table_widget.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)  # 内部滚动条始终可见  
        self.table_widget.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn) # 内部水平滚动条可见

    def create_action(self, name, slot, icon_name=None):
            """
            创建菜单项或工具栏按钮的辅助函数
            :param name: 按钮名称
            :param slot: 按钮点击时触发的槽函数
            :param icon_name: 图标名称（从系统图标库中加载）
            :return: QAction 对象
            """
            action = QAction(name, self)
            if icon_name:
                action.setIcon(QIcon.fromTheme(icon_name))  # 从系统图标库加载图标
            action.triggered.connect(slot)
            return action

        # 菜单项和工具栏按钮的槽函数
    def new_file(self):
        QMessageBox.information(self, "新建", "新建文件")

    def open_file(self):
        QMessageBox.information(self, "打开", "打开文件")

    def save_file(self):
        QMessageBox.information(self, "保存", "保存文件")

    def print_file(self):
        QMessageBox.information(self, "打印", "打印文件")

    def exit_app(self):
        self.close()

    def undo(self):
        QMessageBox.information(self, "撤销", "撤销操作")

    def redo(self):
        QMessageBox.information(self, "重做", "重做操作")

    def cut(self):
        QMessageBox.information(self, "剪切", "剪切操作")

    def copy(self):
        QMessageBox.information(self, "复制", "复制操作")

    def paste(self):
        QMessageBox.information(self, "粘贴", "粘贴操作")

    def delete(self):
        QMessageBox.information(self, "删除", "删除操作")

    def insert(self):
        QMessageBox.information(self, "插入", "插入操作")

    def find(self):
        QMessageBox.information(self, "查找", "查找操作")

    def connect_to_file(self):
        QMessageBox.information(self, "连接到文件", "连接到文件")

    def connect_to_database(self):
        QMessageBox.information(self, "连接到数据库", "连接到数据库")

    def filter_data(self):
        QMessageBox.information(self, "数据筛选", "数据筛选")

    def show_help(self):
        QMessageBox.information(self, "帮助文档", "帮助文档")

    def register(self):
        QMessageBox.information(self, "注册", "注册")

    def about(self):
        QMessageBox.information(self, "关于", "关于本软件")

    def handle_cell_click(self, row, column):
        if column == 0:
            self.table_widget.selectRow(row)

    def load_excel(self):
        file_path, _ = QFileDialog.getOpenFileName(self, "打开 Excel 文件", "", "Excel Files (*.xlsx *.xls)")
        if file_path:
            self.clear_table()
            self.text_suggestion.setText("")  # 清空文本框内容
            self.text_source.setText("")  # 清空文本框内容
            self.display_excel_data(file_path)

    def display_excel_data(self, file_path):
        df = pd.read_excel(file_path)
        file_name = os.path.splitext(os.path.basename(file_path))[0]

        self.table_widget.setRowCount(df.shape[0])
        self.table_widget.setColumnCount(df.shape[1] + 1)

        self.table_widget.setHorizontalHeaderLabels(["文件名"] + df.columns.tolist())
        for i in range(0, self.table_widget.rowCount()):
            self.table_widget.setItem(i, 0, QTableWidgetItem(file_name))

        for i in range(df.shape[0]):
            for j in range(df.shape[1]):
                item = QTableWidgetItem(str(df.iat[i, j]))
                item.setTextAlignment(Qt.AlignCenter)
                self.table_widget.setItem(i, j + 1, item)

        self.table_widget.resizeColumnsToContents()

    def open_input_dialog(self):
        self.clear_table()
        self.text_suggestion.setText("")  # 清空文本框内容
        self.text_source.setText("")  # 清空文本框内容
        if self.table_widget.columnCount() == 0:
            self.init_table_with_headers()
        dialog = InputDialog(self)
        dialog.exec()

    def init_table_with_headers(self):
        headers = ["文件名", "夹杂物序号", "Ca", "Ce", "Mg", "Al", "Li", "Si", "B", "V", "Mn", "Nb", "Cr", "Fe", "Na", "K", "C", "N", "O", "F", "S", "Cl"]
        self.table_widget.setColumnCount(len(headers))
        self.table_widget.setHorizontalHeaderLabels(headers)
        self.table_widget.setRowCount(0)

    def clear_table(self):
        self.table_widget.setRowCount(0)

    def convert_elements(self):
        self.text_suggestion.setText("")  # 清空文本框内容
        self.text_source.setText("")  # 清空文本框内容
        selected_rows = self.table_widget.selectedItems()
        if selected_rows:
            # 获取选中行的索引（这里假设只选中了一行，若允许多选需做相应调整）
            selected_row_index = selected_rows[0].row()
            # 从第3列开始获取对应单元格的数据并赋值给element_mass_fractions字典,初始化
            for col_index in range(2, self.table_widget.columnCount()):
                element_name = self.table_widget.horizontalHeaderItem(col_index).text()
                cell_value = self.table_widget.item(selected_row_index, col_index).text()
                element_mass_fractions[element_name] = float(cell_value)

            # 创建新字典存储摩尔数计算结果
            element_molar_numbers = {}
            for elem in element_mass_fractions.keys():
                if element_mass_fractions[elem] == 0:
                    element_molar_numbers[elem] = 0
                else:
                    element_molar_numbers[elem] = (element_mass_fractions[elem] * total_mass) / element_molar_mass[elem]

            # 定义一个通用函数用于计算化合物生成量，调整函数参数以接收两个字典
            def calculate_compound_amount(compounds, element_molar_numbers, element_molar_mass):
                results = {}
                for compound, comp in compounds.items():
                    first_element = next(iter(comp.keys()))
                    limiting = min(element_molar_numbers[first_element] / comp[first_element],
                                   element_molar_numbers['F'] / comp['F'] if 'F' in comp else np.inf,
                                   element_molar_numbers['O'] / comp['O'] if 'O' in comp else np.inf,
                                   element_molar_numbers['N'] / comp['N'] if 'N' in comp else np.inf,
                                   element_molar_numbers['S'] / comp['S'] if 'S' in comp else np.inf)
                    mass = limiting * comp['M']
                    results[compound] = mass
                    element_molar_numbers[first_element] -= limiting * comp[first_element]
                    if 'F' in comp:
                        element_molar_numbers['F'] -= limiting * comp['F']
                    if 'O' in comp:
                        element_molar_numbers['O'] -= limiting * comp['O']
                    if 'N' in comp:
                        element_molar_numbers['N'] -= limiting * comp['N']
                    if 'S' in comp:
                        element_molar_numbers['S'] -= limiting * comp['S']
                return results

             # 获取选中的行
            selected_row = self.table_widget.currentRow()
            
            # 提取文件名和夹杂物序号
            if selected_row >= 0:  # 确保有选中行
                file_name = self.table_widget.item(selected_row, 0).text()  # 第一列：文件名
                inclusion_index = self.table_widget.item(selected_row, 1).text()  # 第二列：夹杂物序号
            else:
                # 如果没有选中行，可以选择如何处理，例如返回或显示错误消息
                return

            # 计算氟化物生成
            fluorides = {
                'CaF': {'Ca': 1, 'F': 2, 'M': 59.08}
            }
            fluoride_results = calculate_compound_amount(fluorides, element_molar_numbers, element_molar_mass)

            # 计算氧化物生成
            oxides = {
                'CaO': {'Ca': 1, 'O': 1, 'M': 56.08},
                'CeO': {'Ce': 1, 'O': 1, 'M': 156.12},
                'MgO': {'Mg': 1, 'O': 1, 'M': 40.31},
                'Al2O3': {'Al': 2, 'O': 3, 'M': 101.96},
                'Ti2O3': {'Ti': 2, 'O': 3, 'M': 143.74},
                'Li2O': {'Li': 2, 'O': 1, 'M': 29.88},
                'SiO2': {'Si': 1, 'O': 2, 'M': 60.09},
                'B2O3': {'B': 2, 'O': 3, 'M': 69.62},
                'V2O3': {'V': 2, 'O': 3, 'M': 149.88},
                'MnO': {'Mn': 1, 'O': 1, 'M': 70.94},
                'NbO2': {'Nb': 1, 'O': 2, 'M': 124.91},
                'Cr2O3': {'Cr': 2, 'O': 3, 'M': 152},
                'FeO': {'Fe': 1, 'O': 1, 'M': 71.85},
                'Na2O': {'Na': 2, 'O': 1, 'M': 62},
                'K2O': {'K': 2, 'O': 1, 'M': 79.8}
            }

            # 计算氮化物生成
            nitrides = {
                'TiN': {'Ti': 1, 'N': 1, 'M': 61.88},
                'AlN': {'Al': 1, 'N': 1, 'M': 40.99}
            }
            nitride_results = calculate_compound_amount(nitrides, element_molar_numbers, element_molar_mass)

            # 计算硫化物生成
            sulfides = {
                'CeS': {'Ce': 1, 'S': 1, 'M': 172.18},
                'TiS': {'Ti': 1, 'S': 1, 'M': 79.93},
                'MnS': {'Mn': 1, 'S': 1, 'M': 87}
            }
            sulfide_results = calculate_compound_amount(sulfides, element_molar_numbers, element_molar_mass)

            # 计算氧化物生成
            oxide_results = calculate_compound_amount(oxides, element_molar_numbers, element_molar_mass)

            # 清空氧化物生成结果表格
            self.oxide_results_table.setRowCount(0)

            # 插入一行结果
            row_position = self.oxide_results_table.rowCount()
            self.oxide_results_table.insertRow(row_position)

            # 添加文件夹名和夹杂物序号
            file_name_item = QTableWidgetItem(file_name)
            file_name_item.setTextAlignment(Qt.AlignCenter)  # 设置居中对齐
            self.oxide_results_table.setItem(row_position, 0, file_name_item)  # 文件夹名

            inclusion_index_item = QTableWidgetItem(inclusion_index)
            inclusion_index_item.setTextAlignment(Qt.AlignCenter)  # 设置居中对齐
            self.oxide_results_table.setItem(row_position, 1, inclusion_index_item)  # 夹杂物序号

            # 将结果填入新的表格
            for i, header in enumerate(self.column_headers[2:], start=2):  # 从第3列开始填充结果
                if header in oxide_results:
                    item = QTableWidgetItem(f"{oxide_results[header] / total_mass:.2f}")
                elif header in nitride_results:
                    item = QTableWidgetItem(f"{nitride_results[header] / total_mass:.2f}")
                elif header in sulfide_results:
                    item = QTableWidgetItem(f"{sulfide_results[header] / total_mass:.2f}")
                else:
                    item = QTableWidgetItem("0.00")
                item.setTextAlignment(Qt.AlignCenter)
                self.oxide_results_table.setItem(row_position, i, item)
            
            # 返回source_elementsfangfa所有需要的结果  
            return fluoride_results, oxide_results, nitride_results, sulfide_results

    def source_elements(self):

        # 获取convert_elements计算的结果  
        fluoride_results, oxide_results, nitride_results, sulfide_results = self.convert_elements() 
        try:  
            # 清除现有的图表  
            self.ax.clear()  
            
            # 设置全局字体样式  
            plt.rcParams['font.family'] = 'Times New Roman'  # 设置全局字体  
            plt.rcParams['font.size'] = 10  # 设置全局字体大小  
            plt.rcParams['axes.linewidth'] = 1.5  # 设置坐标轴线条粗细  
            
            # 合并所有结果  
            all_results = {}  
            # 添加各类化合物结果  
            for results_dict in [fluoride_results, oxide_results, nitride_results, sulfide_results]:  
                for compound, mass in results_dict.items():  
                    all_results[compound] = mass / total_mass   # 直接转换为百分数  
            
            # 获取化合物名称和对应的百分比值  
            compounds = list(all_results.keys())  
            percentages = [all_results[compound] for compound in compounds]  

            # 转换化学式，添加下标  
            formatted_compounds = []  
            for compound in compounds:  
                # 使用正则表达式将数字转换为下标格式  
                formatted = re.sub(r'(\d+)', r'$_{\\mathregular{\1}}$', compound)  
                formatted_compounds.append(formatted)  

            # 创建柱状图  
            bars = self.ax.bar(range(len(compounds)), percentages,  
                            color='SteelBlue',  # 设置柱子颜色  
                            edgecolor='black',  # 设置边框颜色  
                            linewidth=1,  # 设置边框粗细  
                            alpha=1)  # 设置透明度   

            # 设置图表标题  
            self.ax.set_title('夹杂物组成分布',   
                            fontproperties="SimHei",  # 中文用黑体  
                            fontsize=14,             # 标题字号  
                            fontweight='bold',       # 标题加粗  
                            pad=15)                  # 标题距离图表的距离  

            # 设置y轴标签  
            self.ax.set_ylabel('质量百分含量/%',   
                            fontproperties="SimHei",  # 中文用黑体  
                            fontsize=12,             # 字号  
                            fontweight='bold',       # 加粗  
                            labelpad=10)             # 标签距离轴的距离  

            # 设置y轴的范围和刻度  
            self.ax.set_ylim(0, 100)  # 设置y轴范围从0到100  
            y_ticks = range(0, 101, 20)  # 创建一个从0到100，步长为20的刻度列表  
            self.ax.set_yticks(y_ticks)  # 设置y轴刻度  

            # 设置刻度标签格式  
            def format_func(value, tick_number):  
                return f"{value:.0f}"  # 不带小数点  
            self.ax.yaxis.set_major_formatter(FuncFormatter(format_func))  

            # 设置x轴刻度位置和标签  
            self.ax.set_xticks(range(len(compounds)))  
            self.ax.set_xticklabels(formatted_compounds,   
                                rotation=45,  # 标签旋转45度  
                                ha='right',   # 水平对齐方式  
                                fontsize=10)  # 字体大小  

            # 设置x轴刻度样式  
            self.ax.tick_params(axis='x',               
                            labelsize=10,           # 刻度标签字号  
                            length=3,               # 刻度线长度  
                            width=1,                # 刻度线宽度  
                            direction='in',         # 刻度线朝向  
                            top=False)              # 不显示上边框刻度线  

            # 设置y轴刻度样式  
            self.ax.tick_params(axis='y',               
                            labelsize=10,           # 刻度标签字号  
                            length=3,               # 刻度线长度  
                            width=1,                # 刻度线宽度  
                            direction='in',         # 刻度线朝向  
                            right=False)            # 不显示右边框刻度线  

            # 设置坐标轴线条样式，只显示底部和左侧边框  
            self.ax.spines['top'].set_visible(True)    # 隐藏顶部边框  
            self.ax.spines['right'].set_visible(True)  # 隐藏右侧边框  
            self.ax.spines['bottom'].set_linewidth(1.5) # 设置底部边框线条粗细  
            self.ax.spines['left'].set_linewidth(1.5)   # 设置左侧边框线条粗细  

            # 在柱子上添加数值标签  
            for bar in bars:  
                height = bar.get_height()  
                if height > 0.0:  # 只有当值大于0时才显示标签  
                    self.ax.text(bar.get_x() + bar.get_width()/2., height,  
                            f'{height:.2f}',  
                            ha='center',   
                            va='bottom',   
                            fontsize=8)  

            # 添加网格线  
            self.ax.grid(True,   
                        axis='y',                # 只显示水平网格线  
                        linestyle='--',          # 网格线样式为虚线  
                        alpha=0.3,               # 设置透明度  
                        color='gray')            # 设置颜色  

            # 调整布局，确保标签不被切掉  
            self.canvas.figure.tight_layout()  

            # 重绘图表  
            self.canvas.draw()  

        except Exception as e:  
            # 如果出现错误，在日志文本框中显示错误信息  
            error_message = f"绘制图表时出错: {str(e)}\n"  
            self.log_textbox.append(error_message)
            
        else:
            print("请先选中一行数据再点击成分转换按钮")

        # 设置文本框内容 
        #  
        source_text = "结晶器保护渣卷入"  
        self.text_source.setText(source_text)  # 将文本设置到文本框中
 
    def suggestion_elements(self):  
        # 设置文本框内容  
        suggestion_text = "稳定拉速、稳定过热度、稳定浸入水口插入深度"  
        self.text_suggestion.setText(suggestion_text)  # 将文本设置到文本框中  



class InputDialog(QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.file_name_input = None

        self.table_widget = QTableWidget()
        self.table_widget.setRowCount(3)
        self.table_widget.setColumnCount(22)

        headers = ["文件名", "夹杂物序号", "Ca", "Ce", "Mg", "Al", "Li", "Si", "B", "V", "Mn", "Nb", "Cr", "Fe", "Na", "K", "C", "N", "O", "F", "S", "Cl"]
        self.table_widget.setHorizontalHeaderLabels(headers)

        for row in range(3):
            file_name_edit = QLineEdit()
            self.table_widget.setCellWidget(row, 0, file_name_edit)

        self.button_ok = QPushButton("输入")
        self.button_cancel = QPushButton("取消")

        self.button_ok.clicked.connect(self.accept)
        self.button_cancel.clicked.connect(self.reject)

        layout = QVBoxLayout()
        layout.addWidget(self.table_widget)

        button_layout = QHBoxLayout()
        button_layout.addWidget(self.button_ok)
        button_layout.addWidget(self.button_cancel)

        layout.addLayout(button_layout)
        self.setLayout(layout)

    def accept(self):
        input_data = []
        for row in range(3):
            row_data = []
            for col in range(1, self.table_widget.columnCount()):
                item = self.table_widget.item(row, col)
                row_data.append(item.text() if item else "0")
            input_data.append(row_data)

        file_names = []
        for row in range(3):
            widget = self.table_widget.cellWidget(row, 0)
            if isinstance(widget, QLineEdit):
                file_name = widget.text()
                file_names.append(file_name if file_name else "Manual input")

        print(f"获取到的文件名输入: {file_names}")

        main_window = self.parent()
        main_window.clear_table()

        for row_index, sublist in enumerate(input_data):
            main_window.table_widget.setRowCount(main_window.table_widget.rowCount() + 1)

            file_name = file_names[row_index]

            item = QTableWidgetItem(file_name)
            item.setTextAlignment(Qt.AlignCenter)
            main_window.table_widget.setItem(main_window.table_widget.rowCount() - 1, 0, item)

            for col_index, value in enumerate(sublist, start=0):
                item = QTableWidgetItem(value)
                item.setTextAlignment(Qt.AlignCenter)
                main_window.table_widget.setItem(main_window.table_widget.rowCount() - 1, col_index + 1, item)

        super().accept()

    def showEvent(self, event):
        if isinstance(self, InputDialog):
            col_width = 60
            margin = 50
            width = self.table_widget.columnCount() * col_width + margin
            row_height = 40
            height = self.table_widget.rowCount() * row_height + 100
            self.setGeometry(100, 100, width, height)
            self.setWindowTitle("输入数据")
        super().showEvent(event)


if __name__ == "__main__":
    app = QApplication(sys.argv)
    viewer = ExcelViewer()
    viewer.show()
    sys.exit(app.exec())